package com.huangfuyi.datamodel.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.huangfuyi.common.utils.ObjectUtils;
import com.huangfuyi.datamodel.dao.EDataSourceDao;
import com.huangfuyi.datamodel.entity.datasource.EDataSourceDetailEntity;
import com.huangfuyi.datamodel.entity.datasource.EDataSourceConfExample;
import com.huangfuyi.datamodel.entity.datasource.EDataSourceNodeEntity;
import com.huangfuyi.datamodel.entity.datasource.EDataSourceTypeInfo;
import com.huangfuyi.datamodel.exceptions.EDMDataSourceTreeException;
import com.huangfuyi.datamodel.service.EDataSourceService;
import com.huangfuyi.datasource.annotate.ConnectFieldInfo;
import com.huangfuyi.datasource.entity.EConnectConf;
import com.huangfuyi.datasource.entity.FieldInfoType;
import com.huangfuyi.datasource.entity.query.EDataQueryResult;
import com.huangfuyi.datasource.enums.EDataSourceType;
import com.huangfuyi.datasource.factory.EDataSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;

@Service
public class EDataSourceServiceImpl implements EDataSourceService {

    private final Logger log = LoggerFactory.getLogger(EDataModelInitServiceImpl.class);

    private final String TAG = "数据模型 > 模块初始化业务 ==> ";

    private final List<EDataSourceTypeInfo> dataTypeList = new ArrayList<>();

    private final HashMap<EDataSourceType, List<EDataSourceConfExample>> connectInfoExample = new HashMap<>();

    @Autowired
    private EDataSourceDao dataSourceDao;

    @PostConstruct
    public void init() {
        this.initDataSourceTypeList();
    }

    private void initDataSourceTypeList() {
        this.dataTypeList.clear();
        EDataSourceType[] types = EDataSourceType.values();
        for (EDataSourceType type : types) {
            this.dataTypeList.add(new EDataSourceTypeInfo(type.name(), type.getName(), type.getLabel()));
            try {
                Class<? extends EConnectConf> connectInfoExample = EDataSourceFactory.getConnectInfoExample(type);
                List<EDataSourceConfExample> example = this.initConnectInfoExample(connectInfoExample);
                this.connectInfoExample.put(type, example);
            } catch (Exception e) {
                log.warn("{}初始化数据源配置样例失败！原因：{}", TAG, e.getMessage());
            }
        }
    }

    private List<EDataSourceConfExample> initConnectInfoExample(Class<?> clazz) throws Exception {
        ArrayList<EDataSourceConfExample> result = new ArrayList<>();
        Field[] fields = clazz.getFields();
        Object obj = clazz.newInstance();
        for (Field field : fields) {
            EDataSourceConfExample fieldExampleInfo = new EDataSourceConfExample();
            ConnectFieldInfo fieldAnnotation = field.getAnnotation(ConnectFieldInfo.class);
            if (!ObjectUtils.isEmpty(fieldAnnotation)) {
                fieldExampleInfo.setLabel(fieldAnnotation.label());
                fieldExampleInfo.setDescription(fieldAnnotation.description());
                fieldExampleInfo.setType(fieldAnnotation.type());
                fieldExampleInfo.setEnumValues(Arrays.asList(fieldAnnotation.enumValues().split(";")));
                if (fieldExampleInfo.getType().equals(FieldInfoType.SUBCONFIG)) {
                    Class<?> subClazz = field.getType();
                    fieldExampleInfo.setSubDataSourceFieldInfo(this.initConnectInfoExample(subClazz));
                }
            }
            fieldExampleInfo.setName(field.getName());
            fieldExampleInfo.setValue(field.get(obj));
            result.add(fieldExampleInfo);
        }
        return result;
    }

    @Override
    public int addDataSourceTreeNode(EDataSourceNodeEntity nodeInfo) {
        if (ObjectUtils.isEmpty(nodeInfo.getName())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源节点失败，失败原因：节点name为空", TAG));
        }

        if (ObjectUtils.isEmpty(nodeInfo.getLabel())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源节点失败，失败原因：节点label为空", TAG));
        }

        if (ObjectUtils.isEmpty(nodeInfo.getPid())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源节点失败，失败原因：父节点id为空", TAG));
        }

        nodeInfo.setId(IdUtil.objectId());

        EDataQueryResult parentNode = dataSourceDao.queryTreeNodeById(nodeInfo.getPid(), false);
        if (parentNode.getTotal() <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源节点失败，失败原因：父节点（id:%s）不存在", TAG, nodeInfo.getPid()));
        }
        int insert = dataSourceDao.createTreeNode(nodeInfo);
        if (insert <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源节点失败，失败原因：写入数据库失败。", TAG));
        }
        return insert;
    }

    @Override
    public int deleteDataSourceTreeNode(String nodeId) {
        EDataQueryResult children = dataSourceDao.queryTreeNodeByPId(nodeId, false);
        if (children.getTotal() > 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s删除节点失败！原因：当前节点存在子节点。", TAG));
        }
        int delete = dataSourceDao.deleteTreeNode(nodeId);
        if (delete <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s删除节点失败，失败原因：从数据库删除数据失败。", TAG));
        }
        return delete;
    }

    @Override
    public int updateDataSourceTreeNode(EDataSourceNodeEntity nodeInfo) {
        if (ObjectUtils.isEmpty(nodeInfo.getId())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s修改数据源节点失败，失败原因：节点id为空", TAG));
        }
        int update = dataSourceDao.updateTreeNode(nodeInfo);
        if (update <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s修改节点失败，失败原因：修改数据库数据失败。", TAG));
        }
        return update;
    }

    @Override
    public List<EDataSourceNodeEntity> queryDataSourceTree(String pid) {
        EDataQueryResult treeNodeList = dataSourceDao.queryTreeNodeByPId(pid, true);
        List<Map<String, Object>> data = treeNodeList.getData();
        ArrayList<EDataSourceNodeEntity> results = new ArrayList<>();
        for (Map<String, Object> node : data) {
            results.add(BeanUtil.toBean(node, EDataSourceNodeEntity.class));
        }
        return results;
    }

    @Override
    public int addDataSource(EDataSourceDetailEntity dataSourceDetail) {
        if (ObjectUtils.isEmpty(dataSourceDetail.getName())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源失败，失败原因：数据源name为空", TAG));
        }

        if (ObjectUtils.isEmpty(dataSourceDetail.getType())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源失败，失败原因：数据源类型为空", TAG));
        }

        if (ObjectUtils.isEmpty(dataSourceDetail.getConnectInfos())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源失败，失败原因：数据源连接信息为空", TAG));
        }

        dataSourceDetail.setId(IdUtil.objectId());

        int add = dataSourceDao.addDataSource(dataSourceDetail);
        if (add <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s添加数据源失败，失败原因：写入数据库失败。", TAG));
        }
        return add;
    }

    @Override
    public int deleteDataSource(String dataSourceId) {
        int delete = dataSourceDao.deleteDataSource(dataSourceId);
        if (delete <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s删除数据源失败，失败原因：从数据库删除数据失败。", TAG));
        }
        return delete;
    }

    @Override
    public int updateDataSource(EDataSourceDetailEntity dataSource) {
        if (ObjectUtils.isEmpty(dataSource.getId())) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s修改数据源失败，失败原因：数据源id为空", TAG));
        }
        int update = dataSourceDao.updateDataSource(dataSource);
        if (update <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s修改节点失败，失败原因：修改数据库数据失败。", TAG));
        }
        return update;
    }

    @Override
    public List<EDataSourceDetailEntity> queryDataSourceList(EDataSourceDetailEntity condition, int pageNum, int pageSize) {
        EDataQueryResult dataSourceList = dataSourceDao.queryDataSourceByCondition(condition, pageNum, pageSize);
        List<Map<String, Object>> data = dataSourceList.getData();
        ArrayList<EDataSourceDetailEntity> results = new ArrayList<>();
        for (Map<String, Object> node : data) {
            results.add(BeanUtil.toBean(node, EDataSourceDetailEntity.class));
        }
        return results;
    }

    @Override
    public EDataSourceDetailEntity queryDataSourceDetail(String id) {
        EDataQueryResult dataSourceList = dataSourceDao.queryDataSourceById(id);
        if (dataSourceList.getData().size() <= 0) {
            throw new EDMDataSourceTreeException(String.format(Locale.ROOT, "%s数据源不存在，id:%s", TAG, id));
        }
        return BeanUtil.toBean(dataSourceList.getData().get(0), EDataSourceDetailEntity.class);
    }

    @Override
    public List<EDataSourceTypeInfo> queryDataSourceTypeList() {
        return this.dataTypeList;
    }


    @Override
    public List<EDataSourceConfExample> queryDataSourceConfExample(EDataSourceType type) {
        return this.connectInfoExample.get(type);
    }


}

